package socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Scanner;

/**
 * 聊天室服务端：将服务端听和说的过程定义在了线程里，并在start方法里启用线程
 *
 * @author XingHaiYang
 * @date 2022/9/15 15:21
 */
public class Server3 {
    /**
     * 定义ss对象
     */
    private ServerSocket ss;
    /**
     * 服务端想跟一群客户端交互，那有多少个客户端，服务端就要建立多少个PrintWriter，
     * 每个PrintWriter对应一个客户端，所以这里定义一个PrintWriter的数组
     */
    private PrintWriter[] allOut = {};

    /**
     * 给ss赋值，申请端口号，并监听此端口号
     */
    public Server3() {
        try {
            System.out.println("服务端正在启动...");
            ss = new ServerSocket(8088);
            System.out.println("服务端启动成功！");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     *
     */
    public void start() {
        try {
            System.out.println("等待客户端正在连接...");
            Socket s = ss.accept();
            System.out.println("一个客户端连接成功!");
            //启动线程与该客户端交互
            Runnable r = new ClientHandler(s);
            Thread t = new Thread(r);
            t.start();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 程序的入口
     *
     * @param args
     */
    public static void main(String[] args) {
        Server3 s3 = new Server3();
        s3.start();
    }

    /**
     *
     */
    private class ClientHandler implements Runnable {
        private Socket s;
        private String host;

        public ClientHandler(Socket s) {
            this.s = s;
            host = s.getInetAddress().getHostAddress();
        }

        @Override
        public void run() {
            PrintWriter pw = null;
            try {
                //服务端在主动听
                InputStream in = s.getInputStream();
                InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8);
                BufferedReader br = new BufferedReader(isr);
                String listen;//服务端在听
                while ((listen = br.readLine()) != null) {
                    System.out.println("客户端说：" + listen);
                }
                //服务端主动说
                OutputStream out = s.getOutputStream();
                OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8);
                BufferedWriter bw = new BufferedWriter(osw);
                pw = new PrintWriter(bw, true);
                synchronized (Server3.this) {
                    //对PrintWriter数组进行扩容，来一个客户端扩容一个
                    Arrays.copyOf(allOut, allOut.length + 1);
                    allOut[allOut.length - 1] = pw;
                }
                sendMessage(host + "上线了，当前在线人数：" + allOut.length);
                /*Scanner scan = new Scanner(System.in);
                while(true){
                   String say = scan.nextLine();//服务端在说
                    if("exit".equals(say)){//服务端说exit后，结束通话
                        break;
                    }
                    pw.println(say);
                    System.out.println("服务端说："+say);
                }*/
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                synchronized (Server3.this) {
                    for (int i = 0; i < allOut.length; i++) {
                        if (allOut[i] == pw) {
                            allOut[i] = allOut[allOut.length - 1];
                            Arrays.copyOf(allOut, allOut.length - 1);
                        }
                    }
                }
                System.out.println(host + "下线了，当前在线人数：" + allOut.length);
                try {
                    s.close();//关闭socket，释放资源
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        /**
         * 广播消息给每一个客户端
         */
        private void sendMessage(String line) {
            System.out.println(line);
            //发消息给客户端
            synchronized (Server3.this) {
                for (int i = 0; i < allOut.length; i++) {
                    allOut[i].println(line);
                }
            }
        }
    }
}
